package fr.mywiki.view.web.struts.form.modeling;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import org.apache.struts.action.ActionForm;
import org.jdom.JDOMException;

import fr.mywiki.business.entry.meta.EntryModel;
import fr.mywiki.business.entry.meta.EntryModelManager;
import fr.mywiki.business.entry.meta.ModelException;
import fr.mywiki.business.entry.meta.Property;
import fr.mywiki.business.entry.meta.datatype.DataTypeManager;
import fr.mywiki.business.utils.StringUtils;
import fr.mywiki.model.ejbAdapter.utils.PersistenceException;

/** Formular dedicated to the creation of a model. */
public class EditModelForm extends ActionForm {
	private static final long serialVersionUID = 1L;

	/* The errors */
	public static final String ERROR_NAME_ALREADY_USED_CREATION = "model.create.name.used";
	public static final String ERROR_NAME_ALREADY_USED_EDITION = "model.modify.name.used";
	public static final String ERROR_NAME_EMPTY = "model.create.name.empty";
	
	/* The modes */
	public static final String MODE_CREATION = "mode_creation";
	public static final String MODE_EDITION = "mode_edition";
	
	/** The mode of the formular : creation or edition */
	private String mode;
	
	/** The name of the model */
	private String name;
	
	/** The identifier of the modified model */
	private Long modelId = null;
	
	/** The different properties of the model */
	private List properties;
	
	/** The currently modified property index */
	private int savedIndex;
	
	/** The different data types (to be displayed and used in the formular */
	private List dataTypes;
	
	/** The selected data type index (in the data types collection) */
	private Integer selectedType;
	
	/** The locale of the current user. */
	private Locale locale;
	
	/** The search string (to add a potential object) */ 
	private String searchString;
	
	/** Type of action done on the the property : creation or edition */
	private String propertyAction;
	
	/* Types of actions on the properties */
	public static final String PROPERTY_ACTION_CREATION = "propertyActionCreate";
	public static final String PROPERTY_ACTION_MODIFICATION = "propertyActionModify";
	
	/* The elements of the currently edited property */
	/** Name of the edited property */
	private String editedName;
	/** Type of the edited property */
	private String editedType;
	/** Requirement of the edited property */
	private String editedRequired;
	/** Specifications : use min value */
	private String editedUseMinValue;
	/** Specifications : use max value */
	private String editedUseMaxValue;
	/** Specifications : min and max values and dates */
	private String editedMinValue, editedMaxValue;
	/** Specifications : list of potentials */
	private Set editedPotentials;
	
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	/** Initializes the formular in case of a creation */
	public void initCreate(Locale locale) {
		init(MODE_CREATION, null, locale);
	}

	/**
	 * Initializes the formular in case of the edition of the given
	 * <code>EntryModel</code> object.
	 */
	public void initEdit(EntryModel model, Locale locale) {
		init(MODE_EDITION, model, locale);
	}
	
	private void init(String mode, EntryModel model, Locale locale) {
		this.mode = mode;
		this.locale = locale;
		this.searchString = null;
		
		resetEditedProperty();
		
		boolean modelGiven = (model!=null);
		
		// Identifier of the model
		this.modelId = modelGiven ? model.getId():null;
		
		// Name of the model
		this.name = modelGiven ? model.getName():null;
		
		// Properties of the model
		this.properties = modelGiven ? new ArrayList(model.getProperties()) : new ArrayList();
		
		// Datatypes : loaded from EditionModelProperty
		this.dataTypes = DataTypeManager.getDataTypes(locale);
	}
	
	public void resetEditedProperty() {
		this.editedName = "";
		this.editedType = "";
		this.editedRequired = "";
		this.editedUseMinValue = "";
		this.editedUseMaxValue = "";
		this.editedPotentials = new HashSet();
	}
	
	/**
	 * Checks if the formular has been correctly filled.
	 * 
	 * @return null if there was no error, the error code otherwise.
	 */
	public String check() throws SQLException, ModelException,
			PersistenceException, JDOMException {
		// Name is mandatory
		if(StringUtils.isNullOrEmpty(getName()))
			return ERROR_NAME_EMPTY;
		
		// Creation : name must be unique
		if (MODE_CREATION.equals(getMode())
				&& EntryModelManager.existsModel(getName()))
			return ERROR_NAME_ALREADY_USED_CREATION;
		
		// Modification : name must remain unique
		if (MODE_EDITION.equals(getMode())) {
			ArrayList models = new ArrayList(EntryModelManager.findModelsByName(name));
			if (!models.isEmpty()) {
				EntryModel otherModel = (EntryModel) models.get(0);
				if (models.size() > 1 || !otherModel.getId().equals(modelId))
					return ERROR_NAME_ALREADY_USED_EDITION;
			}
		}
		
		return null;
	}

	public String getMode() {
		return mode;
	}

	public void setMode(String mode) {
		this.mode = mode;
	}

	public Long getModelId() {
		return modelId;
	}

	public void setModelId(Long modelId) {
		this.modelId = modelId;
	}

	public List getProperties() {
		return properties;
	}

	public void setProperties(List properties) {
		this.properties = properties;
	}

	public int getSavedIndex() {
		return savedIndex;
	}

	public void setSavedIndex(int savedIndex) {
		this.savedIndex = savedIndex;
	}

	public List getDataTypes() {
		return dataTypes;
	}

	public void setDataTypes(List dataTypes) {
		this.dataTypes = dataTypes;
	}

	public Integer getSelectedType() {
		return selectedType;
	}

	public void setSelectedType(Integer selectedType) {
		this.selectedType = selectedType;
	}

	public Locale getLocale() {
		return locale;
	}

	public void setLocale(Locale a_locale) {
		locale = a_locale;
	}
	
	/**
	 * Checks if the name of the property is unique : creation mode
	 * 
	 * @param propName
	 *          property name
	 * @return true if the proposed name is not already used for another property, false otherwise.
	 */
	public boolean checkNameUnicity(String propName) {
		for (int i = 0; i < properties.size(); i++)
			if (propName.equals(((Property) properties.get(i)).getName()))
				return false;
		return true;
	}
	
	/**
	 * Checks if the name of the property is unique : modification mode
	 * 
	 * @param propIndex
	 *          current property index
	 * @param propName
	 *          property name
	 * @return true if the proposed name is unique, false otherwise.
	 */
	public boolean checkNameUnicity(int propIndex, String propName) {
		for (int i = 0; i < properties.size(); i++)
			if (i != propIndex
					&& propName.equals(((Property) properties.get(i)).getName()))
				return false;
		return true;
	}

	public String getSearchString() {
		return searchString;
	}

	public void setSearchString(String searchString) {
		this.searchString = searchString;
	}

	public String getEditedName() {
		return editedName;
	}

	public void setEditedName(String editedName) {
		this.editedName = editedName;
	}

	public String getEditedRequired() {
		return editedRequired;
	}

	public void setEditedRequired(String editedRequired) {
		this.editedRequired = editedRequired;
	}

	public String getPropertyAction() {
		return propertyAction;
	}

	public void setPropertyAction(String propertyAction) {
		this.propertyAction = propertyAction;
	}

	public String getEditedType() {
		return editedType;
	}

	public void setEditedType(String editedType) {
		this.editedType = editedType;
	}

	public String getEditedUseMaxValue() {
		return editedUseMaxValue;
	}

	public void setEditedUseMaxValue(String editedUseMaxValue) {
		this.editedUseMaxValue = editedUseMaxValue;
	}

	public String getEditedUseMinValue() {
		return editedUseMinValue;
	}

	public void setEditedUseMinValue(String editedUseMinValue) {
		this.editedUseMinValue = editedUseMinValue;
	}

	public String getEditedMinValue() {
		return editedMinValue;
	}

	public void setEditedMinValue(String a_editedMinValue) {
		editedMinValue = a_editedMinValue;
	}

	public String getEditedMaxValue() {
		return editedMaxValue;
	}

	public void setEditedMaxValue(String a_editedMaxValue) {
		editedMaxValue = a_editedMaxValue;
	}

	public Set getEditedPotentials() {
		return editedPotentials;
	}
	
	public String getEditedPotentialsString() {
		return StringUtils.toString(new ArrayList(getEditedPotentials()));
	}

	public void setEditedPotentials(Set editedPotentials) {
		this.editedPotentials = editedPotentials;
	}
}
